﻿using ApiConceptsFramework.Concepts.Properties;
using ApiConceptsFramework.Contract;
using FluentAssertions;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace test.ApiConceptsFramework.Concepts.Properties
{
	[TestFixture]
	public class NumberOfMembersTests
	{
// ReSharper disable UnusedMember.Local
		class TestClassBase
		{
			public void Method4() { } //methods of the base class should also be included
			public void Method5() { }
		}

		class TestClass : TestClassBase
		{
			public int Field1 = 0;
			public int Field2 = 0;
			public string Property1 { get; set; }
			public string Property2 { get; private set; }
			public string Property3 { private get; set; }
			public void Method1() { }
			public void Method2() { }
			public void Method2(string p1) { } //overloads should not be counted in visual studio
			public void Method3() { }

			//non-public fields should not be counted
#pragma warning disable 0169
			private int _privateField;
#pragma warning restore 0169
			internal int InternalField = 0;
			protected int ProtectedField = 0;
			private void PrivateMethod() { }
			internal void InternalMethod() { }
			protected void ProtectedMethod() { }
			internal string InternalProperty { get; set; }

			//for static members only static members should be counted and vice versa
			public static int StaticField = 0;
			public static void StaticMethod1() { }
			public static void StaticMethod2() { }
			public static void StaticMethod3() { }
		}
// ReSharper restore UnusedMember.Local

		[Test]
		public void Complexity_for_number_of_members_is_correctly_calculated()
		{
			//Arrange
			var measurableProperty = new NumberOfMembers();
			var method = typeof(TestClass).GetMethod("Method1");
			const float expectedResult = 9*NumberOfMembers.NumberOfMembersToComplexityFactor;

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method };
			var result = measurableProperty.CalculateComplexity(target, IDE.VisualStudioOrSimilar);

			//Assert
			result.Should().Be(expectedResult);
			Console.WriteLine("Complexity of Method1 = " + result);
		}

		[Test]
		public void Allows_calculation_for_methods_properties_and_fields()
		{
			//Arrange
			var measurableProperty = new NumberOfMembers();
			var method = typeof(TestClass).GetMethod("Method1");
			var property = typeof(TestClass).GetProperty("Property1");
			var field = typeof(TestClass).GetField("Field1");
			
			//Act
			var resultMethod = measurableProperty.CalculateComplexity(new MeasurableTarget { Type = typeof(TestClass), Member = method }, IDE.VisualStudioOrSimilar);
			var resultProperty = measurableProperty.CalculateComplexity(new MeasurableTarget { Type = typeof(TestClass), Member = property }, IDE.VisualStudioOrSimilar);
			var resultField = measurableProperty.CalculateComplexity(new MeasurableTarget { Type = typeof(TestClass), Member = field }, IDE.VisualStudioOrSimilar);

			//Assert
			resultMethod.Should().Be(resultProperty).And.Be(resultField);
		}

		[Test]
		public void Static_and_public_members_are_not_mixed()
		{
			//Arrange
			var measurableProperty = new NumberOfMembers();
			var method = typeof(TestClass).GetMethod("StaticMethod1");
			const float expectedResult = 3*NumberOfMembers.NumberOfMembersToComplexityFactor;

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method };
			var result = measurableProperty.CalculateComplexity(target, IDE.VisualStudioOrSimilar);

			//Assert
			Assert.AreEqual(expectedResult, result, 0.0001);
			Console.WriteLine("Complexity of StaticMethod1 = " + result);
		}

		[Test]
		public void No_suggestions_are_made()
		{
			//Arrange
			var measurableProperty = new NumberOfMembers();
			var method = typeof(TestClass).GetMethod("Method1");

			//Act
			var target = new MeasurableTarget { Type = typeof(TestClass), Member = method };
			var result = measurableProperty.GetSuggestions(target, IDE.VisualStudioOrSimilar);

			//Assert
			result.Should().BeEmpty();
		}
	}
}
